"""
main_server.py
"""
from flask import Flask, request, jsonify
from threading import Thread
from typing import Optional
import traceback
from datetime import datetime
import numpy as np
import json
from dataclasses import asdict
import time

from typing import Tuple, Dict, Any

from commons.conf import config
from commons.logger import logger

from server.detect import process_detect

from server.api_params_def import (
    DetectInputParams,
    ConfigInfo,
    DetectOutputParams
)



app = Flask(__name__)


def validate_input(data: Dict[str, Any]) -> Tuple[bool, str]:
    """
    验证输入参数
    返回: (是否有效, 错误信息)
    """
    # 检查顶层必需字段
    required_fields = ['timestamp', 'image_base64']
    for field in required_fields:
        if field not in data:
            return False, f"Missing required field: {field}"
        if data[field] is None or data[field] == "":
            return False, f"Field cannot be empty: {field}"

    # 验证时间戳格式
    try:
        datetime.fromisoformat(data['timestamp'])
    except ValueError:
        return False, "Invalid timestamp format. Expected ISO format (e.g., 2024-01-01T12:00:00)"

    return True, ""


class NumpyEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, np.ndarray):
            return obj.tolist()
        if isinstance(obj, datetime):
            return obj.isoformat()
        return super().default(obj)


# 错误处理装饰器
def handle_exceptions(func):
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except Exception as e:
            error_msg = f"Error in {func.__name__}: {str(e)}\n{traceback.format_exc()}"
            logger.error(error_msg)
            return jsonify({
                "result": "error",
                "msg": str(e),
                "data": None
            }), 500
    wrapper.__name__ = func.__name__
    return wrapper


@app.route('/health', methods=['GET'])
@handle_exceptions
def health_check():
    """健康检查接口"""
    return jsonify({
        "result": "ok",
        "msg": "Service is running",
        "data": None
    })


@app.route('/detect', methods=['POST'])
@handle_exceptions
def detect():
    """诊断接口"""
    try:
        data = request.get_json()
        if not data:
            return jsonify({
                "result": "error",
                "msg": "Request body cannot be empty",
                "data": None
            }), 400

        # 验证输入参数
        is_valid, error_message = validate_input(data)
        if not is_valid:
            return jsonify({
                "result": "error",
                "msg": error_message,
                "data": None
            }), 400

        # 构造输入参数
        input_params = DetectInputParams(
            timestamp=datetime.fromisoformat(data['timestamp']),
            image_base64=data['image_base64']
        )

        conf_threshold = config.read_float_conf("detect", "conf_threshold")
        plot_result = config.read_bool_conf("detect", "plot_result")

        configInfo = ConfigInfo(
            conf_threshold=conf_threshold,
            plot_result=plot_result,
        )

        # 处理诊断请求
        output_params = process_detect(input_params, configInfo)

        # 根据error_code构造返回结果
        if output_params.error_code == 0:
            response = {
                "result": "ok",
                "msg": "",
                "data": json.loads(json.dumps(asdict(output_params), cls=NumpyEncoder))
            }
        else:
            response = {
                "result": "error",
                "msg": f"error occurred! code: {output_params.error_msg}",
                "data": json.loads(json.dumps(asdict(output_params), cls=NumpyEncoder))
            }
        return jsonify(response)
    except Exception as e:
        logger.error(f"Error in diagnosis: {str(e)}")
        raise


def get_server_config() -> Tuple[str, int]:
    """获取服务器配置"""
    try:
        host: str = config.read_conf("default", "app_host")
        if host is None:
            host = '0.0.0.0'
            logger.warning("Using default host: 0.0.0.0")

        port: int = config.read_int_conf("default", "app_port", default=28080)
        logger.info(f"Server will start on {host}:{port}")

        return host, port
    except Exception as e:
        logger.error(f"Error reading config: {str(e)}")
        return '0.0.0.0', 28080


def init_app():
    """初始化应用"""
    # 设置日志级别
    # if not app.debug:
    #     logger.setLevel('INFO')

    # 注册错误处理
    @app.errorhandler(404)
    def not_found(error):
        return jsonify({
            "success": False,
            "message": "Route not found"
        }), 404

    @app.errorhandler(405)
    def method_not_allowed(error):
        return jsonify({
            "success": False,
            "message": "Method not allowed"
        }), 405



def start_server():
    """启动服务器"""
    try:
        host, port = get_server_config()
        init_app()

        logger.info("Starting Flask server...")
        app.run(
            debug=True,
            host=host,
            port=port,
            threaded=True
        )
    except Exception as e:
        logger.error(f"Failed to start server: {str(e)}")
        raise


if __name__ == '__main__':
    start_server()